/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.db.explorer.dataview;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.io.ObjectStreamException;
import java.sql.*;
import java.text.MessageFormat;
import java.util.*;
import javax.swing.*;
import javax.swing.DefaultComboBoxModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataEvent;
import javax.swing.table.AbstractTableModel;
import org.openide.DialogDescriptor;
import org.openide.NotifyDescriptor;
import org.openide.TopManager;
import org.openide.awt.SplittedPanel;
import org.openide.nodes.Node;
import org.openide.nodes.NodeTransfer;
import org.openide.util.NbBundle;
import org.openide.util.datatransfer.*;
import org.openide.windows.TopComponent;
import org.netbeans.lib.ddl.DBConnection;
import org.netbeans.modules.db.explorer.infos.*;
import org.netbeans.modules.db.explorer.nodes.*;
public class DataViewWindow extends TopComponent {
private JTextArea queryarea;
private JTable jtable;
private DataModel dbadaptor;
private JComboBox rcmdscombo;
private String schema;
private ResourceBundle bundle;
private Node node;
static final long serialVersionUID =6855188441469780252L;
public DataViewWindow(DatabaseNodeInfo info, String query) throws SQLException {
schema = info.getUser();
node = info.getNode();
try {
bundle = NbBundle.getBundle("org.netbeans.modules.db.resources.Bundle");
setName(bundle.getString("CommandEditorTitle"));
setBorder(new EmptyBorder(new Insets(5,5,5,5)));
GridBagLayout layout = new GridBagLayout();
GridBagConstraints con = new GridBagConstraints ();
setLayout (layout);
// Data model
dbadaptor = new DataModel(info.getDatabaseConnection());
// Query area and button
JPanel subpane = new JPanel();
GridBagLayout sublayout = new GridBagLayout();
GridBagConstraints subcon = new GridBagConstraints ();
subpane.setLayout(sublayout);
subcon.fill = GridBagConstraints.BOTH;
subcon.weightx = 1.0;
subcon.weighty = 1.0;
subcon.gridx = 0;
subcon.gridwidth = 2;
subcon.gridy = 0;
subcon.insets = new java.awt.Insets (0, 0, 5, 0);
queryarea = new JTextArea(query, 3, 70);
queryarea.setLineWrap(true);
queryarea.setWrapStyleWord(true);
queryarea.setDropTarget(new DropTarget(queryarea, new ViewDropTarget()));
JScrollPane scrollpane = new JScrollPane(queryarea);
sublayout.setConstraints(scrollpane, subcon);
subpane.add(scrollpane);
// Combo recent commands
subcon.fill = GridBagConstraints.HORIZONTAL;
subcon.weightx = 1.0;
subcon.weighty = 0.0;
subcon.gridx = 0;
subcon.gridy = 1;
subcon.gridwidth = 1;
subcon.insets = new java.awt.Insets (0, 0, 5, 5);
subcon.anchor = GridBagConstraints.SOUTH;
rcmdscombo = new JComboBox(new ComboModel());
sublayout.setConstraints(rcmdscombo, subcon);
subpane.add(rcmdscombo);
rcmdscombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox source = (JComboBox)e.getSource();
RecentCommand cmd = (RecentCommand)source.getSelectedItem();
if (cmd != null)
setCommand(cmd.getCommand());
}
});
// Button Execute
subcon.gridx = 1;
subcon.gridy = 1;
subcon.weightx = 0.0;
subcon.weighty = 0.0;
subcon.insets = new java.awt.Insets (0, 0, 5, 0);
subcon.fill = GridBagConstraints.HORIZONTAL;
subcon.anchor = GridBagConstraints.SOUTH;
JButton fetchbtn = new JButton(bundle.getString("ExecuteButton"));
sublayout.setConstraints(fetchbtn, subcon);
subpane.add(fetchbtn);
fetchbtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
executeCommand();
}
});
// Table with results
// TableSorter sorter = new TableSorter();
jtable = new JTable(dbadaptor/*sorter*/);
jtable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// sorter.addMouseListenerToHeaderInTable(table);
scrollpane = new JScrollPane(jtable);
// Add it into splitview
con.weightx = 1.0;
con.weighty = 1.0;
con.fill = GridBagConstraints.BOTH;
con.gridx = 0;
con.gridwidth = 1;
con.gridy = 1;
SplittedPanel split = new SplittedPanel();
split.setSplitType(SplittedPanel.VERTICAL);
split.setSplitTypeChangeEnabled(false);
split.setSplitAbsolute(false);
split.setSplitPosition(20);
split.add(subpane, SplittedPanel.ADD_LEFT);
split.add(scrollpane, SplittedPanel.ADD_RIGHT);
layout.setConstraints(split, con);
add(split);
} catch (MissingResourceException e) {
// e.printStackTrace();
}
}
/** Returns query used by panel.
*/
public String getCommand()
{
return queryarea.getText();
}
/** Sets query used by panel.
*/
public void setCommand(String command)
{
queryarea.setText(command);
}
public void executeCommand() {
try {
String command = queryarea.getText().trim();
dbadaptor.execute(command);
RecentCommand rcmd = new RecentCommand(command);
((ComboModel)rcmdscombo.getModel()).addElement(rcmd);
} catch (Exception e) {
TopManager.getDefault().notify(new NotifyDescriptor.Message(bundle.getString("DataViewFetchErrorPrefix") + e.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
}
}
class ColDef
{
private String name;
private boolean writable;
private boolean bric;
int datatype;
public ColDef(String name, boolean flag)
{
this.name = name;
writable = flag;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getDataType()
{
return datatype;
}
public void setDataType(int type)
{
datatype = type;
}
public boolean isWritable()
{
return writable;
}
public void setWritable(boolean flag)
{
writable = flag;
}
public boolean isBestRowIdentifierColumn()
{
return bric;
}
public void setBestRowIdentifierColumn(boolean flag)
{
bric = flag;
}
}
class RecentCommand
{
private String command;
public RecentCommand(String cmd)
{
command = cmd;
}
public String toString()
{
return command;
}
public String getCommand()
{
return command;
}
public boolean equals(Object obj)
{
if (obj instanceof RecentCommand) return ((RecentCommand)obj).getCommand().equals(command);
return super.equals(obj);
}
}
class ComboModel extends AbstractListModel implements MutableComboBoxModel
{
/**
* @associates Object
*/
Vector commands;
Object selected;
static final long serialVersionUID =-5831993904798984334L;
public ComboModel()
{
this(new Vector(1));
}
public ComboModel(Vector elems)
{
commands = elems;
}
public Object getSelectedItem()
{
return selected;
}
public void setSelectedItem(Object anItem)
{
selected = anItem;
fireContentsChanged(this,-1,-1);
}
public void addElement(Object obj)
{
if (!commands.contains(obj)) {
commands.add(obj);
fireContentsChanged(this,-1,-1);
}
}
public void removeElement(Object obj)
{
commands.removeElement(obj);
fireContentsChanged(this,-1,-1);
}
public void insertElementAt(Object obj, int index)
{
if (!commands.contains(obj)) {
commands.insertElementAt(obj, index);
fireContentsChanged(this,-1,-1);
}
}
public void removeElementAt(int index)
{
commands.removeElementAt(index);
fireContentsChanged(this,-1,-1);
}
public int getSize()
{
return commands.size();
}
public Object getElementAt(int index)
{
return commands.get(index);
}
}
class ViewDropTarget implements DropTargetListener
{
/** User is starting to drag over us */
public void dragEnter (DropTargetDragEvent dtde)
{
dtde.acceptDrag(dtde.getDropAction());
}
/** User drags over us */
public void dragOver (DropTargetDragEvent dtde)
{
}
public void dropActionChanged (DropTargetDragEvent dtde)
{
}
/** User exits the dragging */
public void dragExit (DropTargetEvent dte)
{
}
private ColumnNodeInfo getNodeInfo(Transferable t)
{
Node n = NodeTransfer.node(t, NodeTransfer.MOVE);
if (n != null) return (ColumnNodeInfo)n.getCookie(ColumnNodeInfo.class);
n = NodeTransfer.node(t, NodeTransfer.COPY);
if (n != null) return (ColumnNodeInfo)n.getCookie(ColumnNodeInfo.class);
return null;
}
/** Performs the drop action */
public void drop (DropTargetDropEvent dtde)
{
String query = null;
Object obj = null;
Transferable t = dtde.getTransferable();
StringBuffer buff = new StringBuffer();
try {
DataFlavor multiFlavor = new DataFlavor (
NbBundle.getBundle(ExTransferable.class).getString("MultiNodeMimeType"),
NbBundle.getBundle (ExTransferable.class).getString ("transferFlavorsMultiFlavorName")
);
if (t.isDataFlavorSupported(multiFlavor)) {
MultiTransferObject mobj = (MultiTransferObject)t.getTransferData(ExTransferable.multiFlavor);
int count = mobj.getCount();
int tabidx = 0;
HashMap tabidxmap = new HashMap();
for (int i = 0; i < count; i++) {
ColumnNodeInfo nfo = getNodeInfo(mobj.getTransferableAt(i));
if (nfo != null) {
String tablename = nfo.getTable();
Integer tableidx = (Integer)tabidxmap.get(tablename);
if (tableidx == null) tabidxmap.put(tablename, tableidx = new Integer(tabidx++));
if (buff.length()>0) buff.append(", ");
buff.append("t"+tableidx+"."+nfo.getName());
}
}
StringBuffer frombuff = new StringBuffer();
Iterator iter = tabidxmap.keySet().iterator();
while (iter.hasNext()) {
String tab = (String)iter.next();
if (frombuff.length()>0) frombuff.append(", ");
frombuff.append(tab + " t"+tabidxmap.get(tab));
}
query = "select "+buff.toString()+" from "+frombuff.toString();
} else {
ColumnNodeInfo nfo = getNodeInfo(t);
if (nfo != null) query = "select "+nfo.getName()+" from "+nfo.getTable();
}
if (query != null)
setCommand(query);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class DataModel extends AbstractTableModel {
DBConnection dbcon;
/**
* @associates ColDef
*/
Vector coldef;
/**
* @associates Vector
*/
Vector data;
boolean editable = false;
static final long serialVersionUID =7729426847826999963L;
/** Constructor */
public DataModel(DBConnection dbcon)
throws SQLException
{
this.dbcon = dbcon;
}
/** Executes command
* @param command SQL Expression
*/
public void execute(String command) throws Exception {
if (command.length() == 0) return;
Connection con = dbcon.createJDBCConnection();
Statement stat = con.createStatement();
ResultSet rs;
if (command.toLowerCase().startsWith("select")) {
rs = stat.executeQuery(command);
ResultSetMetaData mdata = rs.getMetaData();
String gschema = null;
int cols = mdata.getColumnCount();
coldef = new Vector(cols);
for(int column = 1; column <= cols; column++) {
ColDef cd = new ColDef(mdata.getColumnLabel(column), mdata.isWritable(column));
cd.setDataType(mdata.getColumnType(column));
coldef.add(cd);
}
// Get all rows.
// In future implementations should be more careful
int rcounter = 0, limit = RootNode.getOption().getFetchLimit();
int step = RootNode.getOption().getFetchStep();
data = new Vector();
while (rs.next()) {
Vector row = new Vector(cols);
for (int column = 1; column <= cols; column++)
row.add(rs.getObject(column));
data.addElement(row);
// Catch row count
if (++rcounter >= limit) {
String[] arr = new String[] {
(new Integer(rcounter)).toString(),
(new Integer(step)).toString()
};
String cancel = bundle.getString("DataViewCancelButton");
String nextset = bundle.getString("DataViewNextFetchButton");
String allset = bundle.getString("DataViewAllFetchButton");
String message = MessageFormat.format(bundle.getString("DataViewMessage"), arr);
NotifyDescriptor ndesc = new NotifyDescriptor(message, bundle.getString("FetchDataTitle"), NotifyDescriptor.YES_NO_CANCEL_OPTION, NotifyDescriptor.QUESTION_MESSAGE, new Object[] {nextset, allset, cancel}, NotifyDescriptor.CANCEL_OPTION);
String retv = (String)TopManager.getDefault().notify(ndesc);
if (retv.equals(allset))
limit = Integer.MAX_VALUE;
else
if (retv.equals(nextset))
limit = limit + step;
else
break;
}
}
/*
// Get best row identifier for update
DatabaseMetaData dmd = con.getMetaData();
rs = dmd.getBestRowIdentifier(con.getCatalog(), schema, mdata.getTableName(), DatabaseMetaData.bestRowSession, false);
while (rs.next()) {
String col = rs.getString("COLUMN_NAME");
Enumeration enu = coldef.elements();
while (enu.hasMoreElements()) {
ColDef cd = (ColDef)enu.nextElement();
if (cd.getName().equals(col)) {
cd.setBestRowIdentifierColumn(true);
break;
}
}
}
*/
rs.close();
fireTableChanged(null);
} else {
if (command.toLowerCase().startsWith("delete") || command.toLowerCase().startsWith("insert") || command.toLowerCase().startsWith("update"))
stat.executeUpdate(command);
else {
stat.execute(command);
//refresh DBExplorer nodes
while (!(node instanceof ConnectionNode))
node = node.getParentNode();
Enumeration nodes = node.getChildren().nodes();
while (nodes.hasMoreElements())
((DatabaseNodeInfo)((Node)nodes.nextElement()).getCookie(DatabaseNodeInfo.class)).refreshChildren();
}
TopManager.getDefault().notify(new NotifyDescriptor.Message(bundle.getString("CommandExecuted"), NotifyDescriptor.INFORMATION_MESSAGE));
}
stat.close();
con.close();
}
/** Returns column name
* @param column Column index
*/
public String getColumnName(int column)
{
if (column < coldef.size()) {
String cname = ((ColDef)coldef.elementAt(column)).getName();
return cname;
}
return "";
}
/** Returns column renderer/editor class
* @param column Column index
*/
public Class getColumnClass(int column)
{
if (column < coldef.size()) {
int coltype = ((ColDef)coldef.elementAt(column)).getDataType();
switch (coltype) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR: return String.class;
case Types.BIT: return Boolean.class;
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER: return Integer.class;
case Types.BIGINT: return Long.class;
case Types.FLOAT:
case Types.DOUBLE: return Double.class;
case Types.DATE: return java.sql.Date.class;
}
}
return Object.class;
}
/** Returns true, if cell is editable
*/
public boolean isCellEditable(int row, int column)
{
if (!editable) return false;
if (column < coldef.size()) return ((ColDef)coldef.elementAt(column)).isWritable();
return false;
}
/** Returns colun count
*/
public int getColumnCount()
{
if (coldef == null) return 0;
return coldef.size();
}
/** Returns row count
*/
public int getRowCount()
{
if (data == null) return 0;
return data.size();
}
/** Returns value at specified position
*/
public Object getValueAt(int aRow, int aColumn)
{
Vector row = null;
if (aRow < data.size()) row = (Vector)data.elementAt(aRow);
if (row != null && aColumn<row.size()) return row.elementAt(aColumn);
return null;
}
private String format(Object value, int type)
{
if (value == null) return "null";
switch(type) {
case Types.INTEGER:
case Types.DOUBLE:
case Types.FLOAT: return value.toString();
case Types.BIT: return ((Boolean)value).booleanValue() ? "1" : "0";
case Types.DATE: return value.toString();
default: return "\""+value.toString()+"\"";
}
}
public void setValueAt(Object value, int row, int column)
{
int enucol = 0;
StringBuffer where = new StringBuffer();
HashMap map = new HashMap();
Enumeration enu = coldef.elements();
while (enu.hasMoreElements()) {
ColDef cd = (ColDef)enu.nextElement();
if (cd.isBestRowIdentifierColumn()) {
String key = cd.getName();
String val = format(getValueAt(row,enucol), cd.getDataType());
if (where.length()>0) where.append(" and ");
where.append(key+" = "+val);
}
enucol++;
}
}
}
protected Object writeReplace() throws ObjectStreamException {
return null;
}
}
/*
* <<Log>>
* 11 Gandalf-post-FCS1.9.1.0 4/10/00 Radko Najman
* 10 Gandalf 1.9 2/10/00 Radko Najman command editor support
* 9 Gandalf 1.8 1/5/00 Jaroslav Tulach Change in notify
* descriptor.
* 8 Gandalf 1.7 11/27/99 Patrik Knakal
* 7 Gandalf 1.6 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 6 Gandalf 1.5 10/10/99 Radko Najman setName("Data View")
* 5 Gandalf 1.4 9/8/99 Slavek Psenicka
* 4 Gandalf 1.3 7/21/99 Slavek Psenicka
* 3 Gandalf 1.2 6/30/99 Ian Formanek NodeTransfer related
* changes to make it compilable
* 2 Gandalf 1.1 6/9/99 Ian Formanek ---- Package Change To
* org.openide ----
* 1 Gandalf 1.0 5/21/99 Slavek Psenicka
* $
*/